001 package net.sourceforge.retroweaver.translator; 002 003 import java.util.HashSet; 004 import java.util.Set; 005 006 import org.objectweb.asm.AnnotationVisitor; 007 import org.objectweb.asm.ClassAdapter; 008 import org.objectweb.asm.ClassVisitor; 009 import org.objectweb.asm.FieldVisitor; 010 import org.objectweb.asm.Label; 011 import org.objectweb.asm.MethodAdapter; 012 import org.objectweb.asm.MethodVisitor; 013 import org.objectweb.asm.Opcodes; 014 import org.objectweb.asm.Type; 015 import org.objectweb.asm.signature.SignatureReader; 016 import org.objectweb.asm.signature.SignatureWriter; 017 018 public class NameTranslatorClassVisitor extends ClassAdapter { 019 020 private final NameTranslator translator; 021 022 public NameTranslatorClassVisitor(final ClassVisitor classVisitor, final NameTranslator translator) { 023 super(classVisitor); 024 this.translator = translator; 025 } 026 027 private Set<String> visitedMethods; 028 029 private String className; 030 031 private String translateSignature(final String signature, boolean type) { 032 if (signature == null) { 033 return null; 034 } 035 SignatureReader r = new SignatureReader(signature); 036 SignatureWriter w = new SignatureWriter() { 037 public void visitClassType(final String name) { 038 String n = translator.getClassMirrorTranslation(name); 039 super.visitClassType(n); 040 } 041 }; 042 043 if (type) { 044 r.acceptType(w); 045 } else { 046 r.accept(w); 047 } 048 return w.toString(); 049 } 050 051 public void visit(final int version, final int access, final String name, 052 final String signature, final String superName, 053 final String[] interfaces) { 054 final String newSuperName = translator.getClassMirrorTranslation(superName); 055 056 String newInterfaces[] = new String[interfaces.length]; 057 for (int i = 0; i < interfaces.length; i++) { 058 newInterfaces[i] = translator.getClassMirrorTranslation(interfaces[i]); 059 } 060 061 className = name; 062 visitedMethods = new HashSet<String>(); 063 064 super.visit(version, access, name, translateSignature(signature, false), newSuperName, newInterfaces); 065 } 066 067 public FieldVisitor visitField(final int access, final String name, 068 final String desc, final String signature, final Object value) { 069 return super.visitField(access, name, 070 translator.getClassMirrorTranslationDescriptor(desc), 071 translateSignature(signature, true), value); 072 } 073 074 public MethodVisitor visitMethod(final int access, final String name, 075 final String desc, final String signature, final String[] exceptions) { 076 077 final String newDesc = translator.translateMethodDescriptor(desc); 078 final String fullDesc = name + newDesc; 079 if (visitedMethods.contains(fullDesc)) { 080 throw new TranslatorException( 081 "Duplicate method after name translation in class " 082 + className + ": " + name + ' ' + newDesc); 083 } 084 visitedMethods.add(fullDesc); 085 086 MethodVisitor mv = super.visitMethod(access, name, newDesc, 087 translateSignature(signature, false), exceptions); 088 return (mv == null)?null:new MethodTranslator(mv); 089 } 090 091 public AnnotationVisitor visitAnnotation(final String desc, final boolean visible) { 092 final String newDesc = translateAnnotationDescriptor(desc); 093 return new AnnotationTranslator(cv.visitAnnotation(newDesc, visible)); 094 } 095 096 private String translateAnnotationDescriptor(final String name) { 097 if ((name == null) || (name.length() == 0)) { 098 return name; 099 } 100 101 if ((name.charAt(0) != 'L') || (name.charAt(name.length()-1) != ';')) { 102 return name; 103 } 104 105 return translator.translateDescriptor(name); 106 } 107 108 private class MethodTranslator extends MethodAdapter { 109 MethodTranslator(MethodVisitor methodVisitor) { 110 super(methodVisitor); 111 } 112 113 public void visitTypeInsn(final int opcode, final String desc) { 114 super.visitTypeInsn(opcode, translator.getClassMirrorTranslationDescriptor(desc)); 115 } 116 117 public void visitFieldInsn(final int opcode, final String owner, 118 final String name, final String desc) { 119 120 String newDesc = translator.getClassMirrorTranslationDescriptor(desc); 121 122 if (opcode == Opcodes.GETSTATIC) { 123 final Mirror mirror = translator.getMirror(owner); 124 if (mirror.hasStaticField(name, newDesc)) { 125 super.visitFieldInsn(opcode, 126 translator.translate(owner), name, newDesc); 127 128 return; 129 } 130 } 131 super.visitFieldInsn(opcode, 132 translator.getClassMirrorTranslation(owner), 133 name, newDesc); 134 } 135 136 public void visitMethodInsn(final int opcode, final String owner, 137 final String name, final String desc) { 138 139 // Special case method invocations for name translation. 140 // Specifically to deal with methods mirrors. 141 String newOwner = owner; 142 int newOpcode = opcode; 143 String newDesc = desc; 144 145 String lookupOwner = owner; 146 while (lookupOwner.startsWith("[")) { 147 lookupOwner = lookupOwner.substring(1); 148 } 149 final Mirror mirror = translator.getMirror(lookupOwner); 150 151 if (mirror.isClassMirror()) { 152 newOwner = translator.translate(owner); 153 } else if ("<init>".equals(name)&&(opcode == Opcodes.INVOKESPECIAL)) { 154 /* Look for an equivalent constructor. For instance, 155 * INVOKESPECIAL, "java/math/BigDecimal", "<init>", "(I)V") 156 * will be transformed as 157 * INVOKESTATIC, "../BigDecimal_", "BigDecimal", "(I)Ljava/math/BigDecimal;" 158 * 159 * the previously constructed object was on top of the stack and the mirror 160 * function has put its result on top, so a SWAP and POP are issued to 161 * discard the previously constructed object and store the new one instead. 162 */ 163 String constructorDesc = desc.substring(0, desc.length()-1) + 'L' + owner + ';'; 164 String constructorName; 165 int i = owner.lastIndexOf('/'); 166 if (i == -1) { 167 constructorName = owner; 168 } else { 169 constructorName = owner.substring(i+1); 170 } 171 if (mirror.hasMethod(owner, constructorName, constructorDesc, Opcodes.INVOKESPECIAL)) { 172 newOwner = translator.translate(owner); 173 174 super.visitMethodInsn(Opcodes.INVOKESTATIC, newOwner, constructorName, 175 constructorDesc); 176 177 super.visitInsn(Opcodes.SWAP); 178 super.visitInsn(Opcodes.POP); 179 super.visitInsn(Opcodes.SWAP); 180 super.visitInsn(Opcodes.POP); 181 return; 182 } 183 } else if (mirror.hasMethod(owner, name, desc, opcode)) { 184 newOwner = translator.translate(owner); 185 newOpcode = Opcodes.INVOKESTATIC; 186 187 // We have to insert the owner into the arguments of the 188 // descriptor 189 if (opcode == Opcodes.INVOKEVIRTUAL) { 190 final Type[] argTypes = Type.getArgumentTypes(desc); 191 final Type[] newArgTypes = new Type[argTypes.length + 1]; 192 newArgTypes[0] = Type.getType("L" + owner + ";"); 193 System.arraycopy(argTypes, 0, newArgTypes, 1, argTypes.length); 194 newDesc = Type.getMethodDescriptor( 195 Type.getReturnType(desc), newArgTypes); 196 } 197 } 198 199 super.visitMethodInsn(newOpcode, newOwner, name, 200 translator.translateMethodDescriptor(newDesc)); 201 } 202 203 public void visitTryCatchBlock(final Label start, final Label end, 204 final Label handler, final String type) { 205 super.visitTryCatchBlock(start, end, handler, translator.translate(type)); 206 } 207 208 public void visitLocalVariable(final String name, final String desc, 209 final String signature, final Label start, final Label end, 210 final int index) { 211 super.visitLocalVariable(name, translator.translateDescriptor(desc), 212 translateSignature(signature, true), start, end, index); 213 } 214 215 public AnnotationVisitor visitAnnotationDefault() { 216 return new AnnotationTranslator(mv.visitAnnotationDefault()); 217 } 218 219 public AnnotationVisitor visitAnnotation( 220 final String desc, 221 final boolean visible) 222 { 223 return new AnnotationTranslator(mv.visitAnnotation(desc, visible)); 224 } 225 226 public AnnotationVisitor visitParameterAnnotation( 227 final int parameter, 228 final String desc, 229 final boolean visible) 230 { 231 return new AnnotationTranslator(mv.visitParameterAnnotation(parameter, desc, visible)); 232 } 233 234 } 235 236 private class AnnotationTranslator implements AnnotationVisitor { 237 238 private final AnnotationVisitor av; 239 240 AnnotationTranslator(final AnnotationVisitor av) { 241 this.av = av; 242 } 243 244 public void visit(final String name, final Object value) { 245 final String newName = translateAnnotationDescriptor(name); 246 av.visit(newName, value); 247 } 248 249 public void visitEnum(final String name, final String desc, final String value) { 250 final String newName = translateAnnotationDescriptor(name); 251 final String newDesc = translateAnnotationDescriptor(desc); 252 av.visitEnum(newName, newDesc, value); 253 } 254 255 public AnnotationVisitor visitAnnotation(final String name, final String desc) { 256 final String newName = translateAnnotationDescriptor(name); 257 return new AnnotationTranslator(av.visitAnnotation(newName, desc)); 258 } 259 260 public AnnotationVisitor visitArray(final String name) { 261 final String newName = translateAnnotationDescriptor(name); 262 return new AnnotationTranslator(av.visitArray(newName)); 263 } 264 265 public void visitEnd() { 266 av.visitEnd(); 267 } 268 269 } 270 }